<body>
  <div id="app"></div>
</body>

<script type="module">
  function createRenderer(optios) {
    // 使用options配置
    const {createElement, setElementText, insert} = optios

    function mountElement(vnode, container) {
      const el = createElement(vnode.type)
      if (typeof vnode.children === 'string') {
        setElementText(el, vnode.children)
      } else if (Array.isArray(vnode.children)) {
        // 子节点是数组，遍历child调用patch挂载他们
        vnode.children.forEach(child => {
          patch(null, child, el)
        })
      }
      // 2、如果 vnode.props 存在才处理它
      if (vnode.props) {
        // 遍历 vnoode.props，调用 setAttribute 将属性设置到元素上
        for (const key in vnode.props) {
          // 2.1 第一种
          // el.setAttribute(key, vnode.props[key])
          // 2.1 第二种方式
          el[key] = vnode.props[key]
        }
      }
      insert(el, container)
    }

    // patch
    function patch(n1, n2, container) {
      if (!n1) {
        mountElement(n2, container) // 如果 n1 不存在意味挂载，调用 mountElement 完成
      } else {
        console.log('n1存在, 意味需要打补丁，暂时没做到')
      }
    }

    function render(vnode, container) {
      if (vnode) {
        // 有新vnode，把新旧的一起传递patch函数，进行补丁
        patch(container._vnode, vnode, container)
      } else {
        if (container._vnode) container.innerHTML = ''
      }
      container._vnode = vnode
    }
    return {render}
  }

  // const vnode = {type: 'h1', children: 'hello'}
  // 子节点是一个数组，props存放属性，class、id、from的action等
  const vnode = {
    type: 'div',
    //1、使用 props 描述一个元素的属性
    props: {
      id: 'foo'
    },
    children: [
      {
        type: 'button',
        children: 'hello,'
      }
    ]
  }
  // 封装 api，不会止步于 浏览器
  const renderer = createRenderer({
    createElement(tag) {
      return document.createElement(tag)
    },
    setElementText(el, text) {
      el.textContent = text
    },
    insert(el, parent, anchor = null) {
      parent.insertBefore(el, anchor)
    }
  })
  renderer.render(vnode, document.querySelector('#app'))

  /*
  传递 patch 函数第一个参数是 null，因为挂在阶段，没有旧的 vnode，递归挂载
  patch第三个传挂载点，当前是el，挂在div上，el就是刚刚创建 元素
  */
</script>
